package com.shiyun.disaster_station.point.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.shiyun.disaster_station.common.ReturnMap;
import com.shiyun.disaster_station.line.bean.po.LineInfoPo;
import com.shiyun.disaster_station.line.dao.LineInfoMapper;
import com.shiyun.disaster_station.point.bean.dto.PointImportDto;
import com.shiyun.disaster_station.point.bean.po.LinePointPo;
import com.shiyun.disaster_station.point.bean.req.PointImportReq;
import com.shiyun.disaster_station.point.bean.vo.PointImportVo;
import com.shiyun.disaster_station.point.dao.LinePointMapper;
import com.shiyun.disaster_station.station.service.StationService;
import com.shiyun.disaster_station.utils.ExcelUtils;
import com.shiyun.disaster_station.utils.FileService;
import com.shiyun.disaster_station.utils.LocUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 类 描 述: 点标识
 * 作   者: 史 云
 * 版   本: 1.0.0
 * 时   间: 2022年01月11日  10:00:00
 */
@Service
public class PointService {
    @Resource
    LineInfoMapper lineInfoMapper;
    @Resource
    LinePointMapper linePointMapper;
    @Resource
    @Lazy
    StationService stationService;
    @Resource
    FileService fileService;

    /**
     * 方法描述: 线路点表示的导入
     * 作    者: 史 云
     * 时    间: 2022年06月02日  11:08:31
     */
    public ReturnMap importPoint(MultipartFile file, List<String> headerTextList, List<String> headerKeyList) {
        // 获取导入的数据
        try {
            // 解析导入的数据
            List<PointImportReq> list = ExcelUtils.importExcel(file, headerTextList, headerKeyList, PointImportReq.class);
            // 判断线路是否一条：每次只能导入一条数据
            Set<String> lineNameSet = list.stream().map(PointImportReq::getLineName).collect(Collectors.toSet());
            if (lineNameSet.size() > 1) {
                return ReturnMap.error(-1, "线路不止一条：" + JSONUtil.toJsonStr(lineNameSet));
            }
            // 获取线路名称和ID
            String lineName = list.get(0).getLineName();
            List<LineInfoPo> lineInfoPoList = lineInfoMapper.selectList(new QueryWrapper<LineInfoPo>().eq("name", lineName));
            if (CollectionUtil.isEmpty(lineInfoPoList)) {
                return ReturnMap.error(-1, "线路不存在：" + lineName);
            }
            if (lineInfoPoList.size() > 1) {
                return ReturnMap.error(-1, "线路多条，请清除多余的数据");
            }
            String lineId = lineInfoPoList.get(0).getId();
            // 获取线路类型
            String type = list.get(0).getType();
            String lineType = "3".equals(type) ? "GT" : "PT";
            // 先删除旧的点标识
            linePointMapper.delete(new QueryWrapper<LinePointPo>().eq("line_id", lineId));
            // 重新计算点
            List<LinePointPo> pointList = getPointList(list, lineId, lineType);
            // 批量新增
            linePointMapper.insertBatchSomeColumn(pointList);
            // 导出JSON文件
            String fileUrl = fileService.uploadFile(getJsonFile(pointList, lineInfoPoList.get(0)));
            // 执行站点里程信息的更新
            stationService.updateStationMileage(lineId);
            return ReturnMap.ok(fileUrl);
        } catch (IOException e) {
            e.printStackTrace();
            return ReturnMap.error(-1, e.getMessage());
        }
    }

    /**
     * 方法描述: 获取点标识
     * 作    者: 史 云
     * 时    间: 2022年06月02日  16:02:58
     */
    private List<LinePointPo> getPointList(List<PointImportReq> list, String lineId, String lineType) {
        List<LinePointPo> pointList = new ArrayList<>(1024);
        AtomicReference<LinePointPo> prePoint = new AtomicReference<>(null);
        AtomicInteger order = new AtomicInteger(0);
        AtomicInteger id = new AtomicInteger(Integer.parseInt(lineId) * 1000_000);
        list.forEach(item -> {
            for (String loc : item.getGps().split(";")) {
                String[] locArr = loc.split(",");
                LinePointPo linePointPo = new LinePointPo();
                linePointPo.setId(id.addAndGet(1));
                // 设置经纬度
                linePointPo.setLon(Double.valueOf(locArr[0]));
                linePointPo.setLat(Double.valueOf(locArr[1]));
                // 设置线路ID
                linePointPo.setLineId(Integer.valueOf(lineId));
                // 线路类型
                linePointPo.setLineType(lineType);
                // 设置序号
                linePointPo.setOrder(order.addAndGet(1));
                // 设置里程
                if (prePoint.get() != null) {
                    linePointPo.setMileage(prePoint.get().getMileage() + LocUtils.calculateKilometre(prePoint.get().getLat(), prePoint.get().getLon(), linePointPo.getLat(), linePointPo.getLon()));
                }
                // 第一个点:0.0
                else {
                    linePointPo.setMileage(0.0);
                }
                // 设置名称
                linePointPo.setName("K" + linePointPo.getMileage().toString().replace(".", "+"));
                pointList.add(linePointPo);
                // 更新上一个点
                prePoint.set(linePointPo);
            }
        });
        return pointList;
    }

    /**
     * 方法描述: 获取JSON文件
     * 作    者: 史 云
     * 时    间: 2022年06月02日  17:15:44
     */
    private File getJsonFile(List<LinePointPo> pointList, LineInfoPo lineInfo) throws IOException {
        PointImportVo pointImportVo = new PointImportVo();
        // 设置线路信息
        pointImportVo.setId(Integer.valueOf(lineInfo.getId()));
        pointImportVo.setName(lineInfo.getName());
        pointImportVo.setCode(lineInfo.getCode());
        String fileName = lineInfo.getUrl();
        // 设置点
        List<PointImportDto> RECORDS = new ArrayList<>(16);
        pointList.forEach(item -> {
            PointImportDto ele = BeanUtil.toBean(item, PointImportDto.class);
            ele.setLine_id(lineInfo.getId());
            RECORDS.add(ele);
        });
        pointImportVo.setRECORDS(RECORDS);
        File file = new File("/file/" + UUID.randomUUID() + "/" + fileName);
        if (!file.getParentFile().exists()) { // 如果父目录不存在，创建父目录
            file.getParentFile().mkdirs();
        }
        if (file.exists()) { // 如果已存在,删除旧文件
            file.delete();
        }
        file.createNewFile();
        OutputStreamWriter writer = new OutputStreamWriter(Files.newOutputStream(file.toPath()));
        writer.write(JSONUtil.toJsonPrettyStr(pointImportVo));
        writer.flush();
        writer.close();
        return file;
    }

    /**
     * 方法描述: 根据线路和里程获取点标识
     * 作    者: 史 云
     * 时    间: 2022年07月19日  17:38:37
     */
    public List<LinePointPo> getPointByMileage(Integer lineId, Double mileageStart, Double mileageEnd) {
        return linePointMapper.selectList(new QueryWrapper<LinePointPo>().eq("line_id", lineId).between("mileage", mileageStart, mileageEnd));
    }

    /**
     * 方法描述: 更新里程
     * 作    者: 史 云
     * 时    间: 2022年07月25日  15:59:45
     */
    public ReturnMap updateMileage(String lineId) {
        // 根据线路ID查询点标识
        List<LinePointPo> pointPoList = linePointMapper.selectList(new QueryWrapper<LinePointPo>().eq("line_id", lineId));
        // 更新里程
        AtomicReference<Double> mileage = new AtomicReference<>(0.0);
        AtomicReference<LinePointPo> prePoint = new AtomicReference<>(pointPoList.get(0));
        pointPoList.forEach(item -> {
            // 判断是否为第一个点
            Double itemMileage = item.getMileage();
            if (itemMileage > 0.0) {
                // 计算里程
                Double mileageDis = LocUtils.calculateKilometre(prePoint.get().getLat(), prePoint.get().getLon(), item.getLat(), item.getLon());
                if(mileageDis>2.0){
                    System.out.println(123);
                }
                Double preMileage = mileage.get();
                double curMileage = preMileage + mileageDis;
                mileage.set(curMileage);
                // 设置里程
                item.setMileage(NumberUtil.round(mileage.get(), 3, RoundingMode.HALF_UP).doubleValue());
                // 设置名称
                item.setName("K" + item.getMileage().toString().replace(StringPool.DOT, StringPool.PLUS));
                prePoint.set(item);
            }
        });
        // 批量更新
        linePointMapper.updateBatch(pointPoList);
        return ReturnMap.ok();
    }
}
